#include "Pch.h"
#include "Application.h"
#include <glad\glad.h>
#include <GLFW\glfw3.h>
#include "Input.h"
#include <glm\glm.hpp>
#include "Render\Buffer.h"
#include "Render\Renderer.h"
namespace Engine
{
	
	Application* Application::ms_Instance = nullptr;
	Application::Application()
	{
		if (ms_Instance == nullptr) {
			ENGINE_INFO("Init Application!");
		}
		ms_Instance = this;
		m_WindowHandle = Window::Create();
		m_WindowHandle->SetEventCallback(BIND_EVENT_FN(OnEvent));
		m_ImGuiLayer = new ImGuiLayer("ImGui Layer");
		PushOverLayer(m_ImGuiLayer);

		m_VertexArray.reset(VertexArray::Create()); 
		float vertexs[3*7] = { 
			-0.5,-0.5,0.0, 1.0,0.0,0.0,1.0,
			0.5,-0.5,0.0, 0.0,1.0,0.0,1.0,
			-0.0,0.5,0.0, 0.0,0.0,1.0,1.0
		};

		m_VertexBuffer.reset(VertexBuffer::Create(vertexs,sizeof(vertexs)));

		BufferLayout layout = {
			{ ShaderDataType::Float3,"v_Position" },
			{ ShaderDataType::Float4,"v_Color" }
		};
		m_VertexBuffer->SetLayout(layout);
		m_VertexArray->SetVertexBuffer(m_VertexBuffer);
		
		unsigned int indices[3] = { 0,1,2 };
		m_IndexBuffer.reset(IndexBuffer::Create(indices,sizeof(indices)/sizeof(uint32_t)));

		m_VertexArray->SetIndexBuffer(m_IndexBuffer);	

		std::string vertexSource = R"(
			#version 460 core
			layout(location = 0) in vec3 v_Position;
			layout(location = 1) in vec4 v_Color;
			out vec3 pos;
			out vec4 color1;
			void main() 
			{
				pos = v_Position+0.5;
				color1 = v_Color;
				gl_Position = vec4(v_Position,1.0);
			}
		)";

		std::string fragmentSource = R"(
			#version 460 core
			layout(location = 0) out vec4 color;
			in vec3 pos;
			in vec4 color1; 
			void main() 
			{
				color = color1;
			}
		)";

		m_ShaderHandle = new Shader(vertexSource, fragmentSource);
		
	}

	Application::~Application()
	{
		delete m_WindowHandle;
	}
	void Application::Run()
	{
		glm::vec4 color = { 0.0f, 0.f, 0.f, 1.000f };
		while (m_IsRunning) 
		{
			RenderCommand::SetClearColor(color);
			RenderCommand::Clear();

			Renderer::BeginScene();
			m_ShaderHandle->Bind();
			Renderer::Submit(m_VertexArray);
			Renderer::EndScene();

			for(Layer* layer : m_LayerStack)
			{
				layer->OnUpdate();
			}

			m_ImGuiLayer->Begin();
			for (Layer* layer : m_LayerStack)
			{
				layer->OnImGui();
			}
			m_ImGuiLayer->End();

			m_WindowHandle->OnUpdate();
		}
	}
	void Application::OnEvent(Event& e)
	{
		EventDispatcher dispatcher(e);
		dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(OnWindowClose));
		for (auto iter = m_LayerStack.end(); iter != m_LayerStack.begin();)
		{
			(*(--iter))->OnEvent(e);
			if (e.Handled) break;
		}
	}

	void Application::PushLayer(Layer* layer)
	{
		m_LayerStack.PushLayer(layer);
	}

	void Application::PushOverLayer(Layer* layer)
	{
		m_LayerStack.PushOverlay(layer);
	}

	bool Application::OnWindowClose(WindowCloseEvent& e)
	{
		m_IsRunning = false;
		return true;
	}
}